package main

/*
有 N 个房间，开始时你位于 0 号房间。每个房间有不同的号码：0，1，2，...，N-1，并且房间里可能有一些钥匙能使你进入下一个房间。

在形式上，对于每个房间 i 都有一个钥匙列表 rooms[i]，每个钥匙 rooms[i][j] 由 [0,1，...，N-1] 中的一个整数表示，其中 N = rooms.length。 钥匙 rooms[i][j] = v 可以打开编号为 v 的房间。

最初，除 0 号房间外的其余所有房间都被锁住。

你可以自由地在房间之间来回走动。//注意这里，相当于每个房间都可以与拥有钥匙的房间联通。

如果能进入每个房间返回 true，否则返回 false。

作者：力扣 (LeetCode)
链接：https://leetcode-cn.com/leetbook/read/queue-stack/gle1r/
来源：力扣（LeetCode）
著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。
*/

import "fmt"

// bfs
func canVisitAllRooms(rooms [][]int) bool {
	visited := make([]bool, len(rooms))
	visited[0] = true
	var queue []int
	queue = append(queue, rooms[0]...)
	var cnt int = 1
	for len(queue) != 0 {
		size := len(queue)
		for i := 0; i < size; i++ {
			head := queue[0]
			queue = queue[1:]
			if !visited[head] {
				visited[head] = true
				queue = append(queue, rooms[head]...)
				cnt++ // 新访问一个房间+1，这里也可以在queue = queue[1:]后处理，当成出队一个访问一个
			}
		}
	}
	return cnt == len(rooms)
}

// dfs
func Dfs(rooms [][]int) bool {
	visited := make([]bool, len(rooms))
	var cnt int
	dfs(rooms, 0, visited, &cnt)
	return cnt == len(rooms)
}

func dfs(rooms [][]int, i int, visited []bool, cnt *int) {
	if visited[i] {
		return
	}
	(*cnt)++
	visited[i] = true
	for _, roomID := range rooms[i] {
		if !visited[roomID] {
			dfs(rooms, roomID, visited, cnt)
		}
	}
}

func main() {
	// canOpen := [][]int{
	// 	{1, 3},
	// 	{3, 0, 1},
	// 	{2},
	// 	{0},
	// }
	canOpen := [][]int{
		{2},
		{},
		{1},
	}

	fmt.Println(canVisitAllRooms(canOpen))
	fmt.Println(Dfs(canOpen))
}
